package com.mmc.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mmc.entity.Department;
import com.mmc.mapper.DepartmentMapper;
import com.mmc.service.DepartmentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 部门服务实现类
 *
 * @author kunfe
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {

    private final DepartmentMapper departmentMapper;

    @Override
    public List<Department> getDeptTree() {
        List<Department> allDepts = list(new LambdaQueryWrapper<Department>()
                .eq(Department::getStatus, 1)
                .orderByAsc(Department::getSort));
        
        return buildTree(allDepts);
    }

    @Override
    public List<Department> getAllDepts(String deptName, Integer status) {
        LambdaQueryWrapper<Department> wrapper = new LambdaQueryWrapper<Department>()
                .like(ObjectUtil.isNotEmpty(deptName), Department::getDeptName, deptName)
                .eq(ObjectUtil.isNotNull(status), Department::getStatus, status)
                .orderByAsc(Department::getSort);
        
        return list(wrapper);
    }

    @Override
    public List<Department> getDeptsByParentId(Long parentId) {
        return list(new LambdaQueryWrapper<Department>()
                .eq(Department::getParentId, parentId)
                .eq(Department::getStatus, 1)
                .orderByAsc(Department::getSort));
    }

    @Override
    public Department getDeptByCode(String deptCode) {
        return getOne(new LambdaQueryWrapper<Department>()
                .eq(Department::getDeptCode, deptCode));
    }

    @Override
    public boolean existsDeptCode(String deptCode, Long excludeId) {
        if (ObjectUtil.isEmpty(deptCode)) {
            return false;
        }
        
        LambdaQueryWrapper<Department> wrapper = new LambdaQueryWrapper<Department>()
                .eq(Department::getDeptCode, deptCode)
                .ne(ObjectUtil.isNotNull(excludeId), Department::getId, excludeId);
        return count(wrapper) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createDept(Department dept) {
        // 检查部门编码是否存在
        if (ObjectUtil.isNotEmpty(dept.getDeptCode()) && existsDeptCode(dept.getDeptCode(), null)) {
            throw new RuntimeException("部门编码已存在");
        }
        
        // 设置默认值
        if (dept.getStatus() == null) {
            dept.setStatus(1);
        }
        if (dept.getSort() == null) {
            dept.setSort(0);
        }
        if (dept.getParentId() == null) {
            dept.setParentId(0L);
        }
        
        // 构建层级路径
        dept.setAncestors(buildAncestors(dept.getParentId()));
        
        return save(dept);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDept(Department dept) {
        Department existDept = getById(dept.getId());
        if (existDept == null) {
            throw new RuntimeException("部门不存在");
        }
        
        // 检查部门编码是否存在
        if (ObjectUtil.isNotEmpty(dept.getDeptCode()) && 
            !dept.getDeptCode().equals(existDept.getDeptCode()) && 
            existsDeptCode(dept.getDeptCode(), dept.getId())) {
            throw new RuntimeException("部门编码已存在");
        }
        
        // 不允许将父部门设置为自己或自己的子部门
        if (dept.getParentId() != null && !dept.getParentId().equals(0L)) {
            if (dept.getParentId().equals(dept.getId())) {
                throw new RuntimeException("不能将父部门设置为自己");
            }
            
            List<Long> childIds = getChildDeptIds(dept.getId());
            if (childIds.contains(dept.getParentId())) {
                throw new RuntimeException("不能将父部门设置为自己的子部门");
            }
        }
        
        // 更新层级路径
        if (dept.getParentId() != null) {
            dept.setAncestors(buildAncestors(dept.getParentId()));
        }
        
        boolean result = updateById(dept);
        
        // 如果父部门发生变化，需要更新所有子部门的层级路径
        if (result && dept.getParentId() != null && !dept.getParentId().equals(existDept.getParentId())) {
            updateChildrenAncestors(dept.getId());
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteDept(Long deptId) {
        // 检查是否有子部门
        if (hasChildren(deptId)) {
            throw new RuntimeException("该部门下还有子部门，无法删除");
        }
        
        // 检查是否有用户
        if (hasUsers(deptId)) {
            throw new RuntimeException("该部门下还有用户，无法删除");
        }
        
        return removeById(deptId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteDept(List<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return false;
        }
        
        // 检查是否有子部门或用户
        for (Long deptId : deptIds) {
            if (hasChildren(deptId)) {
                Department dept = getById(deptId);
                throw new RuntimeException("部门【" + dept.getDeptName() + "】下还有子部门，无法删除");
            }
            
            if (hasUsers(deptId)) {
                Department dept = getById(deptId);
                throw new RuntimeException("部门【" + dept.getDeptName() + "】下还有用户，无法删除");
            }
        }
        
        return removeByIds(deptIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeStatus(Long deptId, Integer status) {
        Department dept = new Department();
        dept.setId(deptId);
        dept.setStatus(status);
        
        return updateById(dept);
    }

    @Override
    public boolean hasChildren(Long deptId) {
        return count(new LambdaQueryWrapper<Department>()
                .eq(Department::getParentId, deptId)) > 0;
    }

    @Override
    public boolean hasUsers(Long deptId) {
        return departmentMapper.countUsersByDeptId(deptId) > 0;
    }

    @Override
    public List<Department> getEnabledDepts() {
        return list(new LambdaQueryWrapper<Department>()
                .eq(Department::getStatus, 1)
                .orderByAsc(Department::getSort));
    }

    /**
     * 构建部门树
     */
    private List<Department> buildTree(List<Department> depts) {
        if (CollUtil.isEmpty(depts)) {
            return new ArrayList<>();
        }
        
        // 获取顶级部门
        List<Department> rootDepts = depts.stream()
                .filter(dept -> dept.getParentId() == null || dept.getParentId().equals(0L))
                .collect(Collectors.toList());
        
        // 递归构建子部门
        for (Department rootDept : rootDepts) {
            rootDept.setChildren(getChildren(rootDept.getId(), depts));
        }
        
        return rootDepts;
    }

    /**
     * 递归获取子部门
     */
    private List<Department> getChildren(Long parentId, List<Department> allDepts) {
        List<Department> children = allDepts.stream()
                .filter(dept -> parentId.equals(dept.getParentId()))
                .collect(Collectors.toList());
        
        for (Department child : children) {
            child.setChildren(getChildren(child.getId(), allDepts));
        }
        
        return children;
    }

    /**
     * 构建层级路径
     */
    private String buildAncestors(Long parentId) {
        if (parentId == null || parentId.equals(0L)) {
            return "0";
        }
        
        Department parent = getById(parentId);
        if (parent == null) {
            return "0";
        }
        
        return parent.getAncestors() + "," + parentId;
    }

    /**
     * 获取所有子部门ID
     */
    private List<Long> getChildDeptIds(Long parentId) {
        List<Long> childIds = new ArrayList<>();
        List<Department> children = list(new LambdaQueryWrapper<Department>()
                .eq(Department::getParentId, parentId));
        
        for (Department child : children) {
            childIds.add(child.getId());
            childIds.addAll(getChildDeptIds(child.getId()));
        }
        
        return childIds;
    }

    /**
     * 更新子部门的层级路径
     */
    private void updateChildrenAncestors(Long deptId) {
        Department dept = getById(deptId);
        if (dept == null) {
            return;
        }
        
        List<Department> children = list(new LambdaQueryWrapper<Department>()
                .eq(Department::getParentId, deptId));
        
        for (Department child : children) {
            child.setAncestors(dept.getAncestors() + "," + deptId);
            updateById(child);
            // 递归更新子部门的子部门
            updateChildrenAncestors(child.getId());
        }
    }
} 